package ms.jacrim.pddl;

import java.util.ArrayList;
import java.util.List;

import ms.jacrim.pddl.evaluator.CostBenefitQuotient;
import ms.utils.XmlFile;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class SolutionEvaluatorManager {
	
	private List<SolutionEvaluator> evaluators = new ArrayList<SolutionEvaluator>();
	
	public void addEvaluator(SolutionEvaluator evaluator) {
		if (evaluator != null)
			evaluators.add(evaluator);
	}
	
	public void removeEvaluator(SolutionEvaluator evaluator) {
		evaluators.remove(evaluator);
	}
	
	public SolutionEvaluator getEvaluator(String name) {
		int idx = indexOf(name);
		return idx >= 0? evaluators.get(idx) : null;
	}
	
	public SolutionEvaluator getEvaluator(int index) {
		return evaluators.get(index);
	}
	
	public int indexOf(String evaluatorName) {
		for(int i = 0; i < Count(); i++)
			if (evaluatorName.equalsIgnoreCase(getEvaluator(i).Name()))
				return i;
		return -1;
	}
	
	public int indexOf(SolutionEvaluator evaluator) {
		return evaluators.indexOf(evaluator);
	}
	
	/**
	 * Return the number of managed evaluators.
	 * @return
	 */
	public int Count() {
		return evaluators.size();
	}

	public void addKnownEvaluators() throws Exception {
		CostBenefitQuotient oc = new CostBenefitQuotient(1);
		oc.loadConfig("conf/ex-pddl.xml");
		addEvaluator(oc);
	}
	
	public void loadConfig(XmlFile config) throws Exception {
		Element root = config.selectSingleNode("evaluators");
		if (root != null)
			loadConfig(root);
	}
	
	public void loadConfig(Element root) throws Exception {
		NodeList nodes = root.getElementsByTagName("add");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element node = (Element) nodes.item(i);
			String className = node.getAttribute("class");
			float coeff = Float.parseFloat(node.getAttribute("coeff"));
			SolutionEvaluator eval = (SolutionEvaluator) Class.forName(className).getConstructor(float.class).newInstance(coeff);
			eval.loadConfig(node);
			addEvaluator(eval);
		}
	}
	
	public float evaluate(PddlSolution solution, boolean showDetailMessage) throws Exception {
		float totalCoeff = 0;
		float totalMark = 0;
		float mark;
		for(SolutionEvaluator eval: evaluators)
			if (eval.getCoefficence() > 0) {
				totalCoeff += eval.getCoefficence();
				totalMark += (mark = eval.evaluate(solution)) * eval.getCoefficence();
				if (showDetailMessage) {
					System.out.printf("Performed %s, result is: %f * %f.\r\n", eval.Name(), mark, eval.getCoefficence());
				}
			}
		float result = totalMark / (totalCoeff > 0? totalCoeff: 1);
		if (showDetailMessage) 
			System.out.printf("Average result is: %f.\r\n", result);
		return result;
	}
	
	public float evaluate(PddlSolution solution) throws Exception {
		float totalCoeff = 0;
		float totalMark = 0;
		for(SolutionEvaluator eval: evaluators)
			if (eval.getCoefficence() > 0) {
				totalCoeff += eval.getCoefficence();
				totalMark += (eval.evaluate(solution)) * eval.getCoefficence();
			}
		float result = totalMark / (totalCoeff > 0? totalCoeff: 1);
		return result;
	}

	public List<SolutionEvaluator> getEvaluators() {
		return evaluators;
	}
}
